/**
 * Copyright © 2011 looty - Textoo
 * @link http://www.textoo.org
 * @link http://code.google.com/p/textoo/
 * @author lab9 - Bertrand Larrieu
 * @mail lab9.fr@gmail.com
 * @version 2.0
 */

package org.looty.core.textoo.format 
{
	import flash.display.*;
	import flash.events.*;
	import flash.geom.*;
	import flash.text.*;
	import flash.utils.*;
	import org.looty.log.*;
	import org.looty.textoo.events.*;
	import org.looty.textoo.format.*;

	public class TextooProps extends EventDispatcher
	{	
		private var _width						:int;
		private var _height						:int;
		private var _size						:Rectangle;
		private var _limits						:Rectangle;
		private var _autoSizeDirection			:String;
		private var _wordWrap					:Boolean;
		private var _embedFonts					:Boolean;
		
		private var _maxLines					:uint;
		private var _length						:uint;		
		
		private var _isOverflowing				:Boolean;
		private var _overflowIndex				:uint;
		private var _richTextOverflow			:String;
		private var _richTextFill				:String;		
		
		private var _richText					:String;
		private var _text						:String;
		private var _eText						:String;
		private var _iText						:String;
		private var _eClassName					:String;
		private var _iClassName					:String;
		private var _isHtml						:Boolean;
		
		private var _originalHtml				:String;
		private var _modifiedHtml				:String;
		private var _textVars					:Dictionary;
		private var _useDeviceFonts				:Boolean;
		private var _isTextLightType			:Boolean;
		
		private var _isReady					:Boolean;
		
		private var _isBitmap					:Boolean;
		private var _isSplitted					:Boolean;
		private var _rendererId					:uint;
		
		private var _sharpness					:int;
		private var _thickness					:int;
		
		private var _bitmapLetterClass			:Class;
		private var _textFieldLetterClass		:Class;
		
		static private const REQUIRE_FORMAT		:TextooEvent = new TextooEvent(TextooEvent.REQUIRE_FORMAT);
		static private const REQUIRE_RENDER		:TextooEvent = new TextooEvent(TextooEvent.REQUIRE_RENDER);
		
		static private const BITMAP_LETTER		:String = "org.looty.textoo.render::BitmapLetter";
		static private const TEXTFIELD_LETTER	:String = "org.looty.textoo.render::TextFieldLetter";
		
		public function TextooProps(width:int, height:int) 
		{
			_width = width;
			_height = height;
			_size = new Rectangle();
			_limits = new Rectangle();
			
			setAutoSizeDirection([AutoSizeDirection.NONE, AutoSizeDirection.HORIZONTAL, AutoSizeDirection.VERTICAL, AutoSizeDirection.BOTH][(int(_height == 0) << 1) | int(_width == 0)]);
			
			_embedFonts = false;
			_useDeviceFonts = true;
			_isTextLightType = true;
			
			_isOverflowing = false;
			_richTextOverflow = "<flashrichtext version=\"1\"/>";
			_richTextFill = "<flashrichtext version=\"1\"/>";
			
			_richText = "<flashrichtext version=\"1\"/>";
			_text = "";
			_eText = "";
			_iText = "";
			_eClassName = "";
			_iClassName = "";
			
			_originalHtml = "";
			_modifiedHtml = "";
			
		}
		
		public function setTextVar(name:String, value:String):void
		{
			if (_textVars == null) _textVars = new Dictionary();
			
			if (_textVars[name] == value) return;
			
			_textVars[name] = value;
			
			replaceTextVars();
		}
		
		private function replaceTextVars():void 
		{			
			var html:String = _originalHtml;
			
			if (_textVars != null && /\$\{\w+\}/.test(html)) 
			{				
				
				var regExp:RegExp;
				
				for (var textVar:String in _textVars) 
				{
					regExp = new RegExp("\\$\\{" + textVar + "\\}", "g");
					html = html.replace(regExp, _textVars[textVar]);		
				}
			}
			
			setModifiedHtml(html);
		}
		
		private function setModifiedHtml(value:String):void
		{
			if (_modifiedHtml == value) return;
			
			_modifiedHtml = value;
			_isHtml = true;			
			_isReady = true;
			dispatchEvent(REQUIRE_FORMAT);
		}		
		
		public function get htmlText():String 
		{
			return _modifiedHtml;
		}
		
		public function setHtmlText(value:String):void 
		{
			_originalHtml = value;
			replaceTextVars();
		}		
		
		public function format(richText:String, text:String, isOverFlowing:Boolean, richTextOverflow:String, overflowIndex:uint):void
		{
			_richText = richText;
			_text = text
			_length = _text.length;
			
			_isOverflowing = isOverFlowing;
			_richTextOverflow = richTextOverflow;
			_overflowIndex = overflowIndex;
		}
		
		public function fillOverflow(props:TextooProps):void
		{
			if (!props.isReady) return;
			_richTextFill = props.richTextOverflow;
			_embedFonts = props._embedFonts;
			_isHtml = false;
			_isReady = true;
			dispatchEvent(REQUIRE_FORMAT);
		}		
		
		public function get richTextFill():String 
		{
			return _richTextFill;
		}
		
		public function get richText():String 
		{
			return _richText;
		}
		
		public function get text():String 
		{
			return _text;
		}		
		
		public function get length():uint 
		{
			return _length;
		}
		
		public function get isOverflowing():Boolean 
		{
			return _isOverflowing;
		}		
		
		public function get richTextOverflow():String 
		{
			return _richTextOverflow;
		}		
		
		public function get overflowIndex():uint 
		{
			return _overflowIndex;
		}
		
		public function setText(value:String):void
		{
			if (_eText == value) return;
			_eText = value;
			buildSpan();
		}
		
		public function get className():String 
		{
			return _eClassName != "" ? _eClassName : _iClassName;
		}
		
		public function setClassName(value:String):void 
		{
			if (_eClassName == value) return;
			_eClassName = value;
			buildSpan();
		}
		
		public function setLocalisation(text:String, className:String):void
		{
			if (_iText == text && _iClassName == className) return;
			_iText = text;
			_iClassName = className;
			buildSpan();
		}
		
		private function buildSpan():void
		{		
			switch(true)
			{
				case _eClassName != "" :
					setHtmlText("<span class='" + _eClassName + "' >" + (_eText != "" ? _eText : _iText) + "</span>");
				break;
				
				case _iClassName != "" :
					setHtmlText("<span class='" + _iClassName + "' >" + (_eText != "" ? _eText : _iText) + "</span>");
				break;
				
				default:
					setHtmlText(_eText != "" ? _eText : _iText);
			}
		}	
		
		public function get width():Number 
		{
			return _width;
		}
		
		public function setWidth(value:Number, isFormating:Boolean = false):void 
		{
			switch(true)
			{
				case value is int:
				break;
				
				case value > 0 :
					value = (value + 1) | 0;
				break;
				
				case value < 0 :
					value = (value - 1) | 0;
				break;
			}
			
			if (_width == value) return;
			_width = value;
			applyLimits();
			if (!isFormating) dispatchEvent(REQUIRE_FORMAT);
		}
		
		public function get height():Number 
		{
			return _height;
		}
		
		public function setHeight(value:Number, isFormating:Boolean = false):void 
		{
			switch(true)
			{
				case value is int:
				break;
				
				case value > 0 :
					value = (value + 1) | 0;
				break;
				
				case value < 0 :
					value = (value - 1) | 0;
				break;
			}
			
			if (_height == value) return;
			_height = value;
			applyLimits();
			if (!isFormating) dispatchEvent(REQUIRE_FORMAT);
		}
		
		public function setSize(width:int, height:int):void
		{
			_size.width = width;
			_size.height = height;
		}
		
		public function get size():Rectangle 
		{
			return _size;
		}		
		
		public function get limits():Rectangle 
		{
			return _limits;
		}		
		
		public function get autoSizeDirection():String 
		{
			return _autoSizeDirection;
		}
		
		public function setAutoSizeDirection(value:String):void 
		{
			if (_autoSizeDirection == value) return;
			
			switch(true)
			{
				case value == AutoSizeDirection.HORIZONTAL:
				case value == AutoSizeDirection.VERTICAL:
				case value == AutoSizeDirection.BOTH:
					applyAutoSizeDirection(value);
				break;
				
				case _autoSizeDirection != AutoSizeDirection.NONE:
					applyAutoSizeDirection(AutoSizeDirection.NONE);
				break;
			}
		}
		
		private function applyAutoSizeDirection(value:String):void
		{
			_autoSizeDirection = value;
			_wordWrap = value == AutoSizeDirection.NONE || value == AutoSizeDirection.VERTICAL;
			applyLimits();
			dispatchEvent(REQUIRE_FORMAT);
		}
		
		private function applyLimits():void
		{
			_limits.width = _autoSizeDirection == AutoSizeDirection.VERTICAL || _autoSizeDirection == AutoSizeDirection.NONE ? _width : 2880;
			_limits.height = _autoSizeDirection == AutoSizeDirection.HORIZONTAL || _autoSizeDirection == AutoSizeDirection.NONE ? _height : 10000;
		}
		
		public function get wordWrap():Boolean 
		{
			return _wordWrap;
		}
		
		public function get maxLines():uint 
		{
			return _maxLines;
		}
		
		public function setMaxLines(value:uint):void 
		{
			if (_maxLines == value) return;
			_maxLines = value;
			dispatchEvent(REQUIRE_FORMAT);
		}
		
		public function get embedFonts():Boolean 
		{
			return !_useDeviceFonts || _embedFonts;
		}
		
		public function setEmbedFonts(value:Boolean):void 
		{
			_embedFonts = value;
		}
		
		public function get useDeviceFonts():Boolean { return _useDeviceFonts; }
		
		public function setUseDeviceFonts(value:Boolean):void 
		{
			if (_useDeviceFonts == value) return;
			_useDeviceFonts = value;
			dispatchEvent(REQUIRE_RENDER);
		}		
		
		public function get textColorType():String 
		{
			return _isTextLightType ? TextColorType.LIGHT_COLOR : TextColorType.DARK_COLOR; 
		}
		
		public function get isTextLightType():Boolean 
		{
			return _isTextLightType;
		}		
		
		public function setTextColorType(value:String):void 
		{
			switch(value)
			{
				case TextColorType.LIGHT_COLOR:
					if (_isTextLightType) return;
					_isTextLightType = true;
					if (_isBitmap && _isSplitted) dispatchEvent(REQUIRE_RENDER);
					
				break;
				
				case TextColorType.DARK_COLOR:
					if (!_isTextLightType) return;
					_isTextLightType = false;
					if (_isBitmap && _isSplitted) dispatchEvent(REQUIRE_RENDER);
				break;
			}			
			
		}	
		
		public function dispose():void
		{
			for (var name:String in _textVars) 
			{
				_textVars[name] = null;
				delete _textVars[name];
			}
			_textVars = null;
		}		
		
		public function get isBitmap():Boolean 
		{
			return _isBitmap;
		}
		
		public function set isBitmap(value:Boolean):void 
		{
			if (_isBitmap == value) return;
			_isBitmap = value;
			applyRendererId();
			dispatchEvent(REQUIRE_RENDER);
		}
		
		public function get isSplitted():Boolean 
		{
			return _isSplitted;
		}
		
		public function set isSplitted(value:Boolean):void 
		{
			if (_isSplitted == value) return;
			_isSplitted = value;
			applyRendererId();
			dispatchEvent(REQUIRE_RENDER);
		}
		
		private function applyRendererId():void
		{
			_rendererId = (int(_isSplitted) << 1) | int(_isBitmap);
		}		
		
		public function get rendererId():uint 
		{
			return _rendererId;
		}
		
		public function get isReady():Boolean 
		{
			return _isReady;
		}
		
		public function get isHtml():Boolean 
		{
			return _isHtml;
		}
		
		public function get sharpness():int 
		{
			return _sharpness;
		}
		
		public function setSharpness(value:int):void 
		{
			if (value < -400) value = -400;
			if (value > 400) value = 400;
			if (_sharpness == value) return;
			_sharpness = value;
			dispatchEvent(REQUIRE_RENDER);
		}
		
		public function get thickness():int 
		{
			return _thickness;
		}
		
		public function setThickness(value:int):void 
		{
			if (value < -200) value = -200;
			if (value > 200) value = 200;
			if (_thickness == value) return;
			_thickness = value;
			dispatchEvent(REQUIRE_RENDER);
		}
		
		public function get bitmapLetterClass():Class 
		{
			return _bitmapLetterClass;
		}
		
		public function setBitmapLetterClass(value:Class):void 
		{
			if (_bitmapLetterClass == value) return;
			
			var desc:XML = describeType(value);
			
			if (!desc.factory.extendsClass.@type.contains(BITMAP_LETTER))
			{
				Looger.error("BitmapLetter Class set to Textoo does not inherit from " + BITMAP_LETTER);
				return;
			}
			
			_bitmapLetterClass = value;
			dispatchEvent(REQUIRE_RENDER);
		}
		
		public function get textFieldLetterClass():Class 
		{
			return _textFieldLetterClass;
		}
		
		public function setTextFieldLetterClass(value:Class):void 
		{
			if (_textFieldLetterClass == value) return;
			
			var desc:XML = describeType(value);
			
			if (!desc.factory.extendsClass.@type.contains(TEXTFIELD_LETTER))
			{
				Looger.error("TextFieldLetter Class set to Textoo does not inherit from " + TEXTFIELD_LETTER);
				return;
			}
			
			_textFieldLetterClass = value;
			dispatchEvent(REQUIRE_RENDER);
		}
		
	}

}